
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Serializable;
import java.io.InputStreamReader;
import java.util.*;

public class MazeServer implements Serializable
{
	
	final int RANDOM_SEED = 55535;
	private int _xpos;
	private int _ypos;
	private int individual_treasures_found;
	static private int _xboundary, _yboundary;
    static private LinkedList<Treasure> Treasure_list; 
	static private int total_num_treasures;
	static private int total_treasures_found;
	static private Map<String, int[]> position_map;

	private LinkedList<Treasure> private_list;
	private Map<String, int[]> private_position_map;

	
	public MazeServer(int thread_id)
	{
		// ctor that is called for ever client thread
		String thread_id_str = Integer.toString(thread_id);
		Random rand = new Random(RANDOM_SEED + thread_id);
		_xpos = rand.nextInt(_xboundary);
		_ypos = rand.nextInt(_xboundary);
		int[] pos_array = {_xpos, _ypos};
		position_map.put(thread_id_str,pos_array);
	}
	
	public MazeServer(int xbound, int ybound)
	{
		//ctor called only once during start up
		Treasure_list = new LinkedList();
		private_list = new LinkedList();
		position_map = new HashMap<String, int[]>();
		private_position_map = new HashMap<String, int[]>();
		
		_xboundary = xbound;
		_yboundary = ybound;
		
		total_num_treasures = xbound;
		total_treasures_found = 0;
		
		CreateTreasures();
	}
	
	public int GetXpos()
	{
		return _xpos;
	}
	
	public int GetYpos()
	{
		return _ypos;
	}
	
	public int GetXBoundary()
	{
		return _xboundary;
	}
	
	public int GetYBoundary()
	{
		return _yboundary;
	}
	
	public int GetIndividualTreasuresFound()
	{
		return individual_treasures_found;
	}
	
	public int GetTotalNumTreasures()
	{
		return total_num_treasures;
	}
	
	public int GetNumTreasuresFound()
	{
		return total_treasures_found;
	}
	
	public LinkedList<Treasure> GetPrivateList()
	{
		return private_list;
	}
	
	public Map<String, int[]> GetPrivateMap()
	{
		return private_position_map;
	}
	
	public void SetXPos(int x)
	{
		_xpos = x;
	}
	
	public void SetYPos(int y)
	{
		_ypos = y;
	}
	
	public void SetXBoundary(int x)
	{
		_xboundary = x;
	}

	public LinkedList<Treasure> GetTreasureList()
	{
		return Treasure_list;
	}
	
	public void SetYBoundary(int y)
	{
		_yboundary = y;
	}
	
	public void CreateTreasures()
	{
		int xb = GetXBoundary();
		int yb = GetYBoundary();
		System.out.println("Treasures created at:-");
		for(int i=0; i<GetTotalNumTreasures(); i++)
		{
			Treasure tr_obj = new Treasure(xb, yb, i);
			Treasure_list.add(tr_obj);
		}
	}
	
	public String GetInputString()
	{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in) );
	    char sample;
	
	    String ret_string = "";

		try
		{
			sample =  (char)br.read();
			switch(sample)
			{
			case 'a': ret_string = "LEFT";
			break;
			case 'd': ret_string = "RIGHT";
			break;
			case 'w': ret_string = "UP";
			break;
			case 's': ret_string = "DOWN";
			break;
			//default: System.out.println("INVALID");
			//break;
			}
		}
		catch (IOException ee)
		{
			
		}
		return ret_string;
	}
	
	public void CopyToPrivateListAndMap()
	{
		this.private_list = Treasure_list;
		this.private_position_map = position_map;
	}
	
	public void CleanUp(int thread_id)
	{
		Iterator iterator = position_map.keySet().iterator();
		String thread_id_str = Integer.toString(thread_id);
		position_map.remove(thread_id_str);
	}
	
	public synchronized void UpdatePosition(int thread_id, String str)
	{
		// check the position_map to see the instantaneous positions of all threads
		// and then decide if the next move is possible or not
		int current_xpos = this._xpos;
		int current_ypos = this._ypos;
		String thread_id_str = Integer.toString(thread_id);
		boolean can_move = true;
		if(str.equals("UP"))
		{
			if(current_ypos < _yboundary)
				current_ypos++;
		}
		
		if(str.equals("DOWN"))
		{
			if(current_ypos > 0)
				current_ypos--;
		}
		
		if(str.equals("RIGHT"))
		{
			if(current_xpos < _xboundary)
				current_xpos++;
		}
		if(str.equals("LEFT"))
		{
			if(current_xpos > 0)
				current_xpos--;
		}
		
		// now, current (x,y) positions will have the next move positions.
		// check if this is feasible
		Iterator iterator = position_map.keySet().iterator();

		while( iterator. hasNext() )
		{
			String th_id = (String)iterator.next();
			if(!th_id.equals(thread_id_str))
			{
			    int[] a = position_map.get(th_id);
			    int x = a[0];
			    int y = a[1];
			    if(current_xpos == x && current_ypos == y)
			    {
			    	can_move = false;
			    	break;
			    }	    
			}
		}
		if(can_move)
	    {
	    	this._xpos = current_xpos;
	    	this._ypos = current_ypos;
	    	
	    	// update the position_map to hold the new postion
	    	int[] arr = {current_xpos, current_ypos};
			position_map.put(thread_id_str, arr);
	    }
		else
		{
			System.out.println("Move Denied!!!");
		}
		TreasureHit();
		CopyToPrivateListAndMap();		
	}
	
	public void TreasureHit()
	{
		int current_xpos = _xpos;
		int current_ypos = _ypos;

		
		for(int z=0;z<Treasure_list.size();z++)
		{
			if((current_xpos == Treasure_list.get(z).tr_xpos) && 
					(current_ypos == Treasure_list.get(z).tr_ypos) && 
					Treasure_list.get(z).visited != true)
			{
				System.out.println("Treasure found at " + "(" + current_xpos + " , " + current_ypos + ")");
				Treasure_list.get(z).visited = true;
				total_treasures_found++;
				this.individual_treasures_found++;
				Treasure_list.remove(z);
			}
		}
	}
		
	public void DisplayPos()
	{
		System.out.println("(Xpos, Ypos) -> " + "(" + this._xpos + " , " + this._ypos + ")");
		System.out.println("No. of remaining treasures = " + (GetTotalNumTreasures() - GetNumTreasuresFound()));
		System.out.println("Your treasure count = " + this.individual_treasures_found);
		
		/*Iterator iterator = position_map.keySet().iterator();
		while( iterator. hasNext() )
		{
			String str = (String)iterator.next();
			System.out.println("String = " + str);
			int[] a = position_map.get(str);
			for(int x = 0; x<a.length; x++)
				System.out.println("value = " + a[x]);

		}*/
		
	}
	/*public static void main(String[] args) 
	{
		MazeServer ms = new MazeServer(6,10);
		ms.UpdatePosition();
	}*/

}

class Treasure implements Serializable
{
	final int RANDOM_SEED = 5555;
	public int tr_xpos;
	public int tr_ypos;
	public boolean visited;
	
	
	public Treasure(int xbound, int ybound, int random_seed)
	{
		Random rand = new Random(RANDOM_SEED + random_seed);
		tr_xpos = rand.nextInt(xbound);
		tr_xpos = rand.nextInt(xbound);
		tr_ypos = rand.nextInt(ybound);
		visited = false;

		System.out.println("(" +tr_xpos + " , " + tr_ypos + ")");
		
	}
}
